package com.hfy.user.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.javafaker.Faker;
import com.hfy.model.dto.post.CreateFavoriteDto;
import com.hfy.model.dto.post.DoCollectDto;
import com.hfy.model.dto.post.PostPostDto;
import com.hfy.model.po.user.UserCommentPo;
import com.hfy.model.po.user.post.*;
import com.hfy.model.vo.post.IndexShowPostVo;
import com.hfy.model.vo.post.PostDetailVo;
import com.hfy.user.mapper.*;
import com.hfy.user.service.InfoService;
import com.hfy.user.service.PostService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import result.Result;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.time.LocalDateTime;
import java.util.*;

import static constants.RedisConstants.POST_VIEW_NUM_KEY;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 韩
 * @since 2024-11-28
 */
@Service
public class PostServiceImpl extends ServiceImpl<PostMapper, PostPo> implements PostService {


    private final static String NAMELESS_AVATAR_URL = "/src/assets/img/index/nameless.jpg";

    @Autowired
    private PostMapper postMapper;

    @Autowired
    private PostDataMapper postDataMapper;
    
    @Autowired
    private PostImagesMapper postImagesMapper;

    @Autowired
    private PostTopicsMapper postTopicsMapper;

    @Autowired
    private InfoMapper infoMapper;

    @Autowired
    private PostDraftMapper postDraftMapper;

    @Autowired
    private PostLikeMapper postLikeMapper;

    @Autowired
    private PostCollectMapper postCollectMapper;

    @Autowired
    private PostFavoriteMapper postFavoriteMapper;

    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private HttpServletRequest request;

    @Autowired
    private InfoService infoService;


    @Override
    public Result postPost(Optional<PostPostDto> optional) {
        if (optional.isEmpty()) {
            return Result.error("传入空参数");
        }
        PostPostDto postPostDto = optional.get();
        String content = postPostDto.getContent();
        String contentText = postPostDto.getContentText();
        String remark = postPostDto.getRemark();
        String account = postPostDto.getAccount();
        Integer topicId = postPostDto.getTopicId();
        Integer wordNum = postPostDto.getWordNum();
        List<String> picList = postPostDto.getPicList();
        Boolean isNameless = postPostDto.getIsNameless();


        PostPo post = BeanUtil.toBean(postPostDto, PostPo.class);
        if (post.getId() == null) {
            // 说明是没有草稿直接发布的，就直接uuid一个即可
            post.setId(RandomUtil.randomInt());
        }
        PostDataPo postData = BeanUtil.toBean(postPostDto, PostDataPo.class);
        if (isNameless) {
            // 是匿名
            Faker faker = new Faker(new Locale("zh-CN"));
            String adjective = faker.name().fullName();
            String name = faker.animal().name();
            String nickname = adjective + "的" + name;
            post.setNickname(nickname);
            post.setAvatar(NAMELESS_AVATAR_URL);
        } else {
            // 实名的话就直接去查account的信息
            UserCommentPo userInfo = infoMapper.getInfoByAccount(Long.valueOf(account));
            post.setAvatar(userInfo.getAvatar());
            post.setNickname(userInfo.getUsername());
        }

        save(post);

        // 设置postImages的值
        ArrayList<PostImagesPo> postImagesList = new ArrayList<>();
        picList.forEach((pic) -> {
            PostImagesPo tempPostImages = new PostImagesPo();
            tempPostImages.setPostId(post.getId());
            tempPostImages.setImageUrl(pic);
            postImagesList.add(tempPostImages);
        });
        postImagesMapper.insert(postImagesList);

        // 设置postData的值
        postData.setPostId(post.getId());
        postDataMapper.insert(postData);


        return Result.ok("操作正确");
    }

    @Override
    public Result getTopics() {

        LambdaQueryWrapper<PostTopicsPo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.select(PostTopicsPo::getId, PostTopicsPo::getTitle).eq(PostTopicsPo::getIsDie, false);
        List<PostTopicsPo> postTopics = postTopicsMapper.selectList(queryWrapper);
        return Result.ok(postTopics);
    }

    @Override
    public Result listDraftsByTimes(Integer postId) {
        // 构建查询条件
        LambdaQueryWrapper<PostDraftPo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(PostDraftPo::getPostId, postId)
                   .eq(PostDraftPo::getIsDie, false)
                   .orderByDesc(PostDraftPo::getUpdateTime);
        
        // 查询草稿列表
        List<PostDraftPo> drafts = postDraftMapper.selectList(queryWrapper);
        
        return Result.ok(drafts);
    }

    @Override
    public Result saveDraft(PostDraftPo draft) {
        // 设置更新时间
        draft.setUpdateTime(LocalDateTime.now());
        draft.setIsDie(false);
        
        // 如果第一次生成草稿就先创建一个新的postId
        if (draft.getPostId() == null) {
            draft.setPostId(Math.abs(RandomUtil.randomInt()));
        }

        postDraftMapper.insert(draft);
        return Result.ok(draft.getPostId());
    }

    @Override
    public Result listAnyPostsByPage(Optional<Integer> lastPostIdOptional, Optional<Integer> pageSizeOptional) {
        // 如果没有postId，就找个最大值
        Integer lastPostId = lastPostIdOptional.orElse(Integer.MAX_VALUE);
        // 默认查5页
        Integer pageSize = pageSizeOptional.orElse(5);
//        Page<PostPo> page = new Page<>(pageNum, pageSize);
//        LambdaQueryWrapper<PostPo> queryWrapper = new LambdaQueryWrapper<>();
//        queryWrapper.eq(PostPo::getIsDie, false)
//                        .orderByDesc(PostPo::getCreateTime)
//                .lt(PostPo::getId, lastPostId);
//        Page<PostPo> postPage = postMapper.selectPage(page, queryWrapper);


//        LambdaQueryWrapper<PostPo> queryWrapper = new LambdaQueryWrapper<>();
//        queryWrapper.eq(PostPo::getIsDie, false)
//                .orderByDesc(PostPo::getCreateTime, PostPo::getId)
//                .lt(PostPo::getId, lastPostId)
//                .last(StringPool.SPACE + "limit " + pageSize);
//        List<PostPo> list = list(queryWrapper);

        List<IndexShowPostVo> list = postMapper.getPostWithData(lastPostId, pageSize);

        list.forEach((post) -> {
            Integer postId = post.getId();
            String key = POST_VIEW_NUM_KEY + postId;
            Long newValue = redisTemplate.opsForValue().increment(key);
            if (newValue >= 10) {
                // 如果现在这个值大于等于100了，就直接把这个key删掉，刷到mysql里
                redisTemplate.delete(key);
                postDataMapper.update(new LambdaUpdateWrapper<PostDataPo>().setSql("view_num = view_num + " + newValue).eq(PostDataPo::getPostId, postId));

            }
        });
        return Result.ok(list);
    }

    @Autowired
    private HttpSession session;
    @Override
    public Result getPostInfo(Optional<Integer> postIdOptional, Optional<Long> accountOptional) {

        if (postIdOptional.isEmpty()) {
            return Result.error("必须指定帖子ID");
        }
        if (accountOptional.isEmpty()) {
            return Result.error("账号不能为空");
        }
        Integer postId = postIdOptional.get();
        Long account = accountOptional.get();

        // 查询帖子信息
        PostPo post = postMapper.selectById(postId);
        if (post == null) {
            return Result.error("该贴子不存在");
        }

        // 查询帖子数据
        PostDataPo postData = postDataMapper.selectOne(
            new LambdaQueryWrapper<PostDataPo>().eq(PostDataPo::getPostId, postId)
        );

        // 使用 Optional 进行判空处理
        postData = Optional.ofNullable(postData)
                .orElse(new PostDataPo());

        // 查询话题信息
        PostTopicsPo postTopic = postTopicsMapper.selectById(post.getTopicId());

        // 查询帖子图片
        List<PostImagesPo> postImages = postImagesMapper.selectList(
            new LambdaQueryWrapper<PostImagesPo>().eq(PostImagesPo::getPostId, postId)
        );
        LambdaQueryWrapper<PostLikePo> postLikeLambdaQueryWrapper = new LambdaQueryWrapper<>();
        postLikeLambdaQueryWrapper.eq(PostLikePo::getAccount, account).eq(PostLikePo::getPostId, postId);
        PostLikePo likeStatus = postLikeMapper.selectOne(postLikeLambdaQueryWrapper);

        LambdaQueryWrapper<PostCollectPo> postCollectLambdaQueryWrapper = new LambdaQueryWrapper<>();
        postCollectLambdaQueryWrapper.eq(PostCollectPo::getAccount, account).eq(PostCollectPo::getPostId, postId);

        Long thePostCollectedCount = postCollectMapper.selectCount(postCollectLambdaQueryWrapper);
        // 构建响应数据
        PostDetailVo postDetailVo = new PostDetailVo();
        postDetailVo.setId(post.getId());
        postDetailVo.setAvatar(post.getAvatar());
        postDetailVo.setNickname(post.getNickname());
        postDetailVo.setAccount(post.getAccount());
        postDetailVo.setIsNameless(post.getIsNameless());
        postDetailVo.setCreateTime(post.getCreateTime());
        postDetailVo.setTopicId(post.getTopicId());
        postDetailVo.setTopicTitle(postTopic.getTitle());
        postDetailVo.setContent(postData.getContent());
        postDetailVo.setContentText(postData.getContentText());
        postDetailVo.setWordNum(postData.getWordNum());
        postDetailVo.setLikeNum(postData.getLikeNum());
        postDetailVo.setCommentNum(postData.getCommentNum());
        postDetailVo.setCollectNum(postData.getCollectNum());
        postDetailVo.setShareNum(postData.getShareNum());
        postDetailVo.setImages(postImages);
        postDetailVo.setIsLiked(likeStatus != null);
        postDetailVo.setIsCollected(thePostCollectedCount > 0);

        return Result.ok(postDetailVo);
    }

    @Override
    @Transactional
    public Result toggleLikePost(Optional<Integer> postIdOptional, Optional<Long> accountOptional) {
        // 完成点赞的逻辑操作
        Integer postId;
        Long account;
        if (postIdOptional.isPresent()) {
            postId = postIdOptional.get();
        } else {
            return Result.error("必须指定帖子");
        }
        if (accountOptional.isPresent()) {
            account = accountOptional.get();
        } else {
            return Result.error("必须有账号");
        }
        // 把现在的喜欢状态
        LambdaQueryWrapper<PostLikePo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(PostLikePo::getPostId, postId).eq(PostLikePo::getAccount, account);
        int deleteCount = postLikeMapper.delete(queryWrapper);
        LambdaUpdateWrapper<PostDataPo> updateWrapper = new LambdaUpdateWrapper<>();
        if (deleteCount > 0) {
            // 取消点赞 减少一个赞
            updateWrapper.setSql("like_num = like_num - 1").eq(PostDataPo::getPostId, postId);
            postDataMapper.update(updateWrapper);
            return Result.ok(false);
        }
        // 未点赞，执行点赞逻辑
        // 点赞 增加一个赞
        updateWrapper.setSql("like_num = like_num + 1").eq(PostDataPo::getPostId, postId);
        postDataMapper.update(updateWrapper);
        PostLikePo postLikePo = new PostLikePo();
        postLikePo.setAccount(account);
        postLikePo.setPostId(postId);
        postLikeMapper.insert(postLikePo);
        return Result.ok(true);
    }

    @Override
    @Transactional
    public Result toggleCollectPost(Optional<DoCollectDto> dtoOptional) {
        // 0. 获取数据与数据校验
        if (dtoOptional.isEmpty()) {
            return Result.error("不能不传参数");
        }
        DoCollectDto dto = dtoOptional.get();
        Integer postId = dto.getPostId().orElseThrow(() -> {
            throw new RuntimeException("收藏文章不能为空");
        });

        Long account = dto.getAccount().orElseThrow(() -> {
            throw new RuntimeException("账号不能为空");
        });
        Integer favoriteId = dto.getFavoriteId();

        // 这里查一下 这个收藏夹是否属于这个账号
        Long num1 = postFavoriteMapper.selectCount(new LambdaQueryWrapper<PostFavoritePo>().eq(PostFavoritePo::getAccount, account).eq(PostFavoritePo::getId, favoriteId));
        if (num1 == null || num1 == 0) {
            return Result.error("该账号无权限操控该账号");
        }

        // 1. 分析业务逻辑，分两个方面，一个是数量上，一个是记录上

        // 2. 先操作记录，先删，删不掉就插入
        LambdaQueryWrapper<PostCollectPo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(PostCollectPo::getFavoriteId, favoriteId)
                    .eq(PostCollectPo::getPostId, postId)
                    .eq(PostCollectPo::getAccount, account); // 其实这个eq没必要写因为别人也无法获取操作到你的收藏夹列表
        int delete = postCollectMapper.delete(queryWrapper);
        // 由于收藏和取消收藏两个方向都需要这段代码，提取出来
        Long num2 = postCollectMapper.selectCount(new LambdaQueryWrapper<PostCollectPo>().eq(PostCollectPo::getAccount, account)
                .eq(PostCollectPo::getPostId, postId));
        if (delete > 0) {
            // 删掉了 说明是取消收藏，然后还需要去看一下 这个文章还有没有被该账户的其他收藏夹收藏
//            PostCollectPo ppp = postCollectMapper.selectOne(new LambdaQueryWrapper<PostCollectPo>().eq(PostCollectPo::getAccount, account)
//                    .eq(PostCollectPo::getPostId, postId));
            if (num2 != null && num2 > 0) {
                // 说明还有别收藏夹收藏， 那么就数量不变，返回的值要置为null，因为我还是收藏了它的，状态没变，数量也没变
                return Result.ok(null);
            }
            // 说明已经没有别的收藏夹收藏了，数量减1
            postDataMapper.update(new LambdaUpdateWrapper<PostDataPo>().setSql("collect_num = collect_num - 1").eq(PostDataPo::getPostId, postId));
            // 并且状态要改成取消收藏
            return Result.ok(false);
        }

        // 没有删掉就是 收藏逻辑
        postCollectMapper.insert(new PostCollectPo(null, account, postId, favoriteId, LocalDateTime.now()));
        if (num2 != null && num2 > 0) {
            // 说明还有别收藏夹收藏， 那么就数量不变，返回的值要置为null，因为我还是收藏了它的，状态没变，数量也没变

            return Result.ok(null);
        }
        // 说明这个账号下已经没有其他收藏夹收藏该帖子了

        // 说明已经没有别的收藏夹收藏了，数量减1
        postDataMapper.update(new LambdaUpdateWrapper<PostDataPo>().setSql("collect_num = collect_num + 1").eq(PostDataPo::getPostId, postId));
        // 并且状态要改成已收藏
        return Result.ok(true);
    }

    @Override
    public Result listFavorites(OptionalLong accountOptional, OptionalInt postIdOptional) {
        // 参数校验
        if (accountOptional.isEmpty()) {
            return Result.error("账号不能为空");
        }
        if (postIdOptional.isEmpty()) {
            return Result.error("帖子不能为空");
        }
        Long account = accountOptional.getAsLong();
        Integer postId = postIdOptional.getAsInt();

        // 查询该用户的所有收藏夹
        LambdaQueryWrapper<PostFavoritePo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(PostFavoritePo::getAccount, account)
                    .orderByDesc(PostFavoritePo::getCreateTime);
        
        List<PostFavoritePo> favorites = postFavoriteMapper.selectList(queryWrapper);
        
        // 查询每个收藏夹中的帖子数量
        favorites.forEach(favorite -> {
            LambdaQueryWrapper<PostCollectPo> collectWrapper = new LambdaQueryWrapper<>();
            collectWrapper.eq(PostCollectPo::getFavoriteId, favorite.getId())
                         .eq(PostCollectPo::getAccount, account);
            long count = postCollectMapper.selectCount(collectWrapper);
            favorite.setCount((int) count);

            collectWrapper = new LambdaQueryWrapper<>();
            collectWrapper.eq(PostCollectPo::getPostId, postId).eq(PostCollectPo::getFavoriteId, favorite.getId())
                    .eq(PostCollectPo::getAccount, account);
            Long count1 = postCollectMapper.selectCount(collectWrapper);
            // 大于0 则是有这个收藏夹里有这个帖子
            favorite.setIsCollected(count1 > 0);

        });

        return Result.ok(favorites);
    }

    @Override
    public Result createFavorite(Optional<CreateFavoriteDto> dtoOptional) {
        // 参数校验
        if (dtoOptional.isEmpty()) {
            return Result.error("参数不能为空");
        }
        CreateFavoriteDto dto = dtoOptional.get();
        
        if (dto.getTitle() == null || dto.getTitle().trim().isEmpty()) {
            return Result.error("收藏夹标题不能为空");
        }
        if (dto.getAccount() == null) {
            return Result.error("账号不能为空");
        }

        // 检查是否已存在同名收藏夹
        LambdaQueryWrapper<PostFavoritePo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(PostFavoritePo::getAccount, dto.getAccount())
                    .eq(PostFavoritePo::getTitle, dto.getTitle().trim());
        Long count = postFavoriteMapper.selectCount(queryWrapper);
        if (count > 0) {
            return Result.error("已存在同名收藏夹");
        }

        // 创建新收藏夹
        PostFavoritePo favorite = new PostFavoritePo();
        favorite.setTitle(dto.getTitle().trim());
        favorite.setAccount(dto.getAccount());
        favorite.setCreateTime(LocalDateTime.now());
        favorite.setCount(0);
        
        postFavoriteMapper.insert(favorite);
        
        return Result.ok();
    }

    @Override
    public Result listMyPosts() {
        // 直接把session里的账号拿出来

        Long account = Long.valueOf((String)session.getAttribute("account"));

        // 如果没有postId，就找个最大值
        List<IndexShowPostVo> list = postMapper.listMyPosts(account);

        return Result.ok(list);
    }

    @Override
    public Result getHotPosts(Optional<Long> accountOptional, Optional<Integer> limitOptional) {
        // 默认查询10条热门帖子
        int limit = limitOptional.orElse(10);
        // 如果没有提供账号，则默认为0（未登录用户）
        Long account = accountOptional.orElse(0L);

        List<IndexShowPostVo> hotPosts = postMapper.getHotPosts(account, limit);

        return Result.ok(hotPosts);
    }
}

